package com.peng.rpc.common.server;

import com.peng.rpc.annotation.Service;
import com.peng.rpc.annotation.ServiceScan;
import com.peng.rpc.enumeration.RpcError;
import com.peng.rpc.exception.RpcException;
import com.peng.rpc.provider.ServiceProvider;
import com.peng.rpc.registry.ServiceRegistry;
import com.peng.rpc.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Set;

/**
 * @author Wonderson
 * @email wpp.ds@foxmail.com
 * @date 2022/3/8 12:55
 */
@Slf4j
public abstract class AbstractRpcServer implements RpcServer{

    protected String host;
    protected int port;

    protected ServiceProvider serviceProvider;
    protected ServiceRegistry serviceRegistry;

    public void servicesScan() {
        String mainClassName = ReflectUtil.getStackTrace();
        Class<?> startClass = null;
        try {
            startClass = Class.forName(mainClassName);
            if (!startClass.isAnnotationPresent(ServiceScan.class)) {
                log.error("启动类缺少@ServiceScan");
                throw new RpcException(RpcError.SERVICE_SCAN_NOT_FOUND);
            }
        } catch (ClassNotFoundException e) {
            log.info("加载主类出现错误：{}", e.getMessage());
        }
        String basePackage = startClass.getAnnotation(ServiceScan.class).value();
        if ("".equals(basePackage)) {
            //没有标注值，按照启动类所在的包作为起始包
            basePackage = mainClassName.substring(0, mainClassName.lastIndexOf("."));
        }
        Set<Class<?>> classes = ReflectUtil.getClasses(basePackage);
        for (Class<?> clazz : classes) {
            if (clazz.isAnnotationPresent(Service.class)) {
                Object obj = null;
                String className = clazz.getAnnotation(Service.class).name();
                try {
                    Constructor<?> constructor = clazz.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    obj = constructor.newInstance();
                } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                    log.error("创建类{}发生错误:{}", clazz, e);
                }
                //注册服务到注册中心和服务列表
                if ("".equals(className)) {
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> anInterface :interfaces){
                        String serviceName = anInterface.getCanonicalName();
                        publishService(obj, serviceName);
                    }
                } else {
                    publishService(obj, className);
                }
            }
        }
    }

    @Override
    public <T> void publishService(T service, String serviceName) {
        serviceProvider.addService(service, serviceName);
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }
}
